﻿using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

namespace Kyoh.Lib.Excel
{
    /// <summary>Excel COM オブジェクトに対するリフレクションを定義します。</summary>
	internal static class Reflect
	{
        /// <summary>オブジェクトのメソッドを呼び出します。</summary>
        /// <param name="obj">オブジェクト。</param>
        /// <param name="methodName">メソッド名。</param>
        /// <param name="arguments">メソッドの引数。</param>
		internal static object InvokeMethod(object obj, string methodName, params object[] arguments)
		{
			return obj.GetType().InvokeMember(methodName, System.Reflection.BindingFlags.InvokeMethod, null, obj, arguments ?? new object[0]);
		}

        /// <summary>オブジェクトのプロパティを取得します。</summary>
        /// <param name="obj">オブジェクト。</param>
        /// <param name="propertyName">プロパティ名。</param>
        /// <param name="arguments">プロパティの引数。</param>
		internal static object GetProperty(object obj, string propertyName, params object[] arguments)
		{
			return obj.GetType().InvokeMember(propertyName, System.Reflection.BindingFlags.GetProperty, null, obj, arguments ?? new object[0]);
		}

        /// <summary>オブジェクトのプロパティを設定します。</summary>
        /// <param name="obj">オブジェクト。</param>
        /// <param name="propertyName">プロパティ名。</param>
        /// <param name="arguments">プロパティの引数。</param>
		internal static void SetProperty(object obj, string propertyName, params object[] arguments)
		{
			obj.GetType().InvokeMember(propertyName, System.Reflection.BindingFlags.SetProperty, null, obj, arguments ?? new object[0]);
		}

        /// <summary>Excel COM オブジェクトの クラス名を取得します。</summary>
        internal static string GetComClassName(object obj)
        {
            var dispatch = (IDispatch)obj;
            uint count;
            dispatch.GetTypeInfoCount(out count);
            if (count < 1)
                throw new InvalidOperationException();
            IntPtr pTypeInfo;
            dispatch.GetTypeInfo(0, 0, out pTypeInfo);
            if (pTypeInfo == IntPtr.Zero)
                throw new InvalidOperationException();
            var typeInfo = (System.Runtime.InteropServices.ComTypes.ITypeInfo)Marshal.GetTypedObjectForIUnknown(pTypeInfo, typeof(ITypeInfo));
            string typeName, document, helpFile;
            int helpContext;
            typeInfo.GetDocumentation(-1, out typeName, out document, out helpContext, out helpFile);
            Marshal.Release(pTypeInfo);
            return typeName;
        }
	}
}
